#!/bin/bash
set -e
source variable.sh
podnetwork=10.244.0.0/16
runtime_type=docker
baseline=129 #default
baseinstall=0
goinstall=0
runcinstall=0
containerdinstall=0
dockerinstall=0
k8sinstall=0
install_on_docker=0
ip=$(hostname -I | awk '{print $1}')
name=$(hostname)
ARCH=`arch`

help() {
    echo "Usage:"
    echo "Install: $0 <-i ONLYINSTALL> <-d DIST> <-b BASELINE>"
    echo "Setup: $0 <-d DIST> <-b BASELINE> <-n NODETYPE> <-t CONTAINERTYPE>"
    echo "Other options: $0 [-c] [-h]"
    echo "Description:"
    echo "without -i will install and setup current node with -d -n and -t"
    echo "-c reset and clean current node"
    echo "-h print help message"
    echo "-i ONLYINSTALL package docker or k8s, without any config"
    echo "-b BASELINE,120, 125, 129"
    echo "-d DIST, ctl2, ctl3, ctl4, oe2309, oe2403,oe2503"
    echo "-n NODETYPE, master or worker"
    echo "-t CONTAINERTYPE, docker or containerd"
    exit -1
}
[[ $# == 0 ]] && help && exit

while getopts 'i:d:n:t::b:uch' OPT; do
    case $OPT in
        i)  case "$OPTARG" in
                "docker"|"k8s")
                    onlyinstall=$OPTARG
                    echo "only install $OPTARG..."
                    ;;
                *)
                    echo "unsupported onlyinstall value $OPTARG..." && exit 1
                    ;;
            esac
            ;;
        d)  case "$OPTARG" in
                "ctl2"|"ctl3"|"ctl4"|"oe2403"|"oe2309"|"oe2503")
                    dist=$OPTARG && echo "dist is set as $OPTARG..."
                    ;;
                *)
                    echo "unsupported dist type $OPTARG..." && exit 1
                    ;;
            esac
            ;;
        n) if [ "$OPTARG" == "master" ] || [ "$OPTARG" == "worker" ];then
               nodetype=$OPTARG && echo "nodetype is set as $OPTARG..."
           else
               echo "unsupport node type $OPTARG..." && exit
           fi
        ;;
        t) if [ "$OPTARG" == "docker" ] || [ "$OPTARG" == "containerd" ];then
               runtime_type=$OPTARG && echo "runtime_type is set as $OPTARG..."
           else
               echo "unsupport container engine type $OPTARG..." && exit
           fi
        ;;
        b)  case "$OPTARG" in
                "120"|"125"|"129")
                baseline=$OPTARG && echo "baseline is set as $OPTARG.."
		        set_version_${OPTARG}
                ;;
            *)
                echo "unsupport k8s baseline $OPTARG.."&& exit 1
                ;;
            esac
            ;;
	u) for package in $online_install_pkg; do
           if rpm -q "$package" > /dev/null 2>&1; then
               rpm -Uvh rpms/$package-*.rpm
           else
               echo "Package $package is not installed, skipping update."
           fi
           done
           exit 0
        ;;
        c) echo "clean k8s setup..."
           kubeadm reset -f
           rm -rf /etc/cni/*
           ifconfig cni0 down > /dev/null 2>&1
           ifconfig flannel.1 down > /dev/null 2>&1
           ifconfig docker0 down > /dev/null 2>&1
           ip link delete cni0 > /dev/null 2>&1
           ip link delete flannel.1 > /dev/null 2>&1
           echo "k8s reset and network all deleted!" && exit
        ;;
        h) help && exit;;
        ?) help && exit;;
    esac
done

# 检查是否指定了 -d 参数
if [ -z "$dist" ]; then
    echo "Error: -d DIST parameter is required."
    help   
fi
if [[ $dist == "ctl4" || $dist == "oe2403" || $dist == "oe2503" ]]; then
    if [[ $baseline != "129" ]]; then
        echo "警告：$dist 发行版必须使用129基线，已忽略指定的基线版本$baseline，并设置为129基线。"
        baseline=129
        set_version_129  # 确保调用正确的版本设置函数
    fi
fi

if [[ $baseline != "120" && "x$runtime_type" == "xdocker" && "x$onlyinstall" != "xdocker" ]]; then
    echo "${baseline}基线暂不支持使用docker部署k8s,该基线只能用-t containerd部署k8s; 仅安装docker请使用 -i docker"
    exit
fi

echo "开始一键安装模式，该过程需要使用root"
[ `whoami` == "root" ] || exit
rpm -q cri-tools || baseinstall=1
if [ $baseinstall -eq 0 ]; then # test:1
     echo "检查到基础库已安装!"
else
     echo -e "\033[44;37m 安装基础库 \033[0m"
     cd rpms
     if [ "$baseline" == "120" ]; then
         rpm -ivh --force --nodeps protobuf-*.rpm zlib-devel-*.rpm vim-filesystem-*.rpm vim-common-*.rpm libnetfilter_queue-*.rpm libnetfilter_cttimeout-*.rpm libnetfilter_cthelper-*.rpm gpm-libs-*.rpm vim-enhanced-*.rpm emacs-filesystem-*.rpm protobuf-devel-*.rpm protobuf-c-*.rpm conntrack-tools-help-*.rpm conntrack-tools-*.rpm socat-*.rpm libcgroup-*.rpm cri-tools-*.rpm
     else
         rpm -ivh --force --nodeps conntrack-tools-*.rpm socat-*.rpm libcgroup-*.rpm container-selinux-*.rpm tar-*.rpm cri-tools-*.rpm
     fi
     cd -
fi
# go version || goinstall=1
# if [ $goinstall -eq  0 ]; then
#      echo "检查到golang已安装!"
# else
#      echo -e "\033[44;37m 安装 golang \033[0m"
#      rpm -ivh rpms/golang-*${dist}*.rpm
# fi
echo -e "\033[44;37m 安装 runc/containerd/docker, 如果有老版本请先自行御载！！！ \033[0m"
runc -v || runcinstall=1
if [ $runcinstall -eq  0 ]; then
     echo "检查到runc已安装!"
else
     echo "安装runc..."
     rpm -ivh rpms/runc-*${dist}.${ARCH}.rpm
fi
containerd -v || containerdinstall=1
if [ $containerdinstall -eq  0 ]; then
     echo "检查到contained已安装!"
else
     echo "安装contained..."
     rpm -ivh rpms/containerd-*${dist}.${ARCH}.rpm
     systemctl enable containerd.service
fi
if [ "x$runtime_type" == "xcontainerd" ];then 
    mkdir -p /etc/containerd && containerd config default | sudo tee /etc/containerd/config.toml > /dev/null 2>&1
    if [ $baseline != "120" ]; then
        sed -i "s#sandbox_image = \"registry.k8s.io/pause:.*\"#sandbox_image = \"${IMAGE_REPO}/pause:${PAUSE_VERSION}\"#" /etc/containerd/config.toml
        sed -i 's#SystemdCgroup = false#SystemdCgroup = true#' /etc/containerd/config.toml 
    else
        #sed -i "s#sandbox_image = \"k8s.gcr.io/pause:.*\"#sandbox_image = \"docker.ctyun.cn:60001/base-x86_64/pause:$PAUSE_VERSION\"#"  /etc/containerd/config.toml
        sed -i "s#sandbox_image = \"k8s.gcr.io/pause:.*\"#sandbox_image = \"${IMAGE_REPO}/pause:${PAUSE_VERSION}\"#"  /etc/containerd/config.toml
    fi
    systemctl restart containerd.service

    sockoption="--cri-socket /run/containerd/containerd.sock"
    sedcmd='-e "s,dockershim.sock,containerd/containerd.sock,g"'
fi

if [[ "x$runtime_type" == "xdocker" || "x$onlyinstall" == "xdocker" ]];then
     docker -v || dockerinstall=1
    if [ $dockerinstall -eq  0 ]; then
        echo "检查到Docker已安装!"
	[ $(rpm -q $(rpm -qf $(which docker)) --qf %{version} | awk -F '.' '{print $1}') -le 18 ] && \
        (rpm -e runc --nodeps; rpm -ivh rpms/runc-*${dist}.${ARCH}.rpm;)
    else
        echo "安装docker..."
        if [ $baseline == "120" ]; then
            dockername="docker"
        else
            dockername="moby"
        fi
        rm -rf /etc/docker/daemon.json #This file should be delete, or start service will fail. Offline mode does NOT need this file
        if [ $baseline == "129" ]; then
            rpm -ivh rpms/libnetwork*.rpm rpms/${dockername}-*${dist}.${ARCH}.rpm
        else
            rpm -ivh rpms/${dockername}-*${dist}.${ARCH}.rpm
        fi
    fi
        systemctl enable docker
        systemctl daemon-reload
        systemctl restart docker
        echo "Docker 安装完成. "
        if [ "x$onlyinstall" == "xdocker" ]; then
            exit
        fi
fi


echo -e "\033[44;37m 安装 k8s \033[0m"
rpm -qa | grep kubelet && k8sinstall=1
if [ $k8sinstall -eq 1 ]; then
    echo "检查到k8s已安装!"
else
    echo "安装k8s rpms..."
    cd rpms
    if [ "$nodetype" == "worker" ];then
        rpm -ivh --nodeps --force kubernetes-kubelet-*${dist}.${ARCH}.rpm kubernetes-client-*${dist}.${ARCH}.rpm kubernetes-node-*${dist}.${ARCH}.rpm kubernetes-kubeadm-*${dist}.${ARCH}.rpm
    elif [ "$nodetype" == "master" ];then
        rpm -ivh --nodeps --force kubernetes-*${dist}.${ARCH}.rpm
    else
        echo "Please specify the 'nodetype' correctly through the '-n' option." && exit
    fi
    cd -
    systemctl enable kubelet
fi

if [ ! -d /opt/cni ];then
    echo -e "\033[44;37m 安装k8s cni插件 \033[0m"
    rpm -ivh rpms/containernetworking-plugins-*${dist}.${ARCH}.rpm
    mkdir -p /opt/cni
    ln -s /usr/libexec/cni /opt/cni/bin
fi


if [ ! -f /etc/kubernetes/admin.conf ];then
    echo -e "\033[44;37m 设置k8s \033[0m"
    iptables -P FORWARD ACCEPT
    systemctl stop firewalld.service
    systemctl disable firewalld.service
    sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
    swapoff -a
    grep ^nameserver /etc/resolv.conf || (chmod a+w /etc/resolv.conf && echo "nameserver 114.114.114.114" >> /etc/resolv.conf)
    modprobe br_netfilter
    sed -i 's/net.ipv4.ip_forward=0/net.ipv4.ip_forward=1/g' /etc/sysctl.conf
    sysctl --system > /dev/null 2>&1
    echo -e "\033[44;37m 加载k8s镜像 \033[0m"
    cd tar-${ARCH}/

    if ls *.tar 1> /dev/null 2>&1; then
        for i in *.tar; do
            if [ "x$runtime_type" == "xdocker" ]; then
                docker load -i "$i"
            else
                ctr -n k8s.io images import "$i"
            fi
        done
        cd -

        if [ "x$onlyinstall" == "xk8s" ]; then
            echo "rpm和镜像已安装完成！" 
            exit
        fi
    else
        echo "没有找到 *.tar 文件，镜像未完成安装。"&& exit
    fi
    

    if [ "$nodetype" == "master" ];then
        kubeadm init $sockoption --image-repository=${IMAGE_REPO} --pod-network-cidr=$podnetwork --apiserver-advertise-address=$ip --kubernetes-version=${KUBERNETES_VERSION}
        #默认使用参数配置（因为可做到无人工修改），也可以解注如下代码并手工修改kubeadm-template.yaml，通过config方式完成init。
        #cp config/kubeadm-template.yaml kubeadm.yaml
        #sed -i -e "s/advertiseAddress: ip/advertiseAddress: $ip/g" -e "s/name: master/name: $name/g" -e "s/ARCH/`arch`/g" $sedcmd kubeadm.yaml
        #kubeadm init --config kubeadm.yaml
        mkdir -p $HOME/.kube
        cp /etc/kubernetes/admin.conf $HOME/.kube/config
        cp /etc/kubernetes/admin.conf ~/.kube/config
        chown $(id -u):$(id -g) $HOME/.kube/config
        sed "s/ARCH/`arch`/g" config/flannel.yaml | kubectl apply -f -
        #mkdir -p /run/flannel;cp config/subnet.env /run/flannel/;cp config/10-flannel.conflist /etc/cni/net.d/ #In case files missing
        sed -i "/--trusted-ca-file=/a \    $etcd_insert_content" /etc/kubernetes/manifests/etcd.yaml
        sed -i "/--tls-private-key-file=/a \    $kube_apiserver_insert_content" /etc/kubernetes/manifests/kube-apiserver.yaml
        sed -i "/--use-service-account-credentials=true/a \    $kube_controller_insert_content" /etc/kubernetes/manifests/kube-controller-manager.yaml
        sed -i "/--leader-elect=true/a \    $kube_scheduler_insert_content" /etc/kubernetes/manifests/kube-scheduler.yaml
        sed -i "$ a\\$kubelet_insert_content" /var/lib/kubelet/config.yaml
        systemctl restart kubelet
        sleep 5
        echo -e "\033[44;37m 去除k8s污点 \033[0m"
        export KUBECONFIG=/etc/kubernetes/admin.conf
        until kubectl get nodes &> /dev/null; do sleep 2; done
        master_name=$(kubectl get nodes -o jsonpath='{.items[?(@.metadata.labels.node-role\.kubernetes\.io/control-plane=="")].metadata.name}')
        if [ -z "$master_name" ]; then
            echo "未找到control-plane节点!"
            exit 1
        fi
        # 获取污点信息
        taints=$(kubectl get node "$master_name" -o jsonpath='{.spec.taints}')
        if [ "$taints" = "null" ] || [ -z "$taints" ]; then
            echo "不存在污点！"
        else
            # 单独删除常见污点
            kubectl taint node --all "$master_name" node-role.kubernetes.io/control-plane- 2>/dev/null ||true
            kubectl taint node --all "$master_name" node-role.kubernetes.io/master- 2>/dev/null|| true
            kubectl taint node --all "$master_name" node.kubernetes.io/not-ready- 2>/dev/null || true
            echo -e "污点已经移除！"
        fi
        #rm -rf kubeadm.yaml
        echo  -e "\033[44;37m master结点全部部署完成，请拷贝kubeadm join命令行备用 \033[0m"
    elif [ "$nodetype" == "worker" ];then 
        echo  -e "\033[44;37m 请执行master配置完成后提示的kubeadm join命令行加入集群 \033[0m"
        echo  -e "\033[44;37m 执行kubeadm join命令加入master后，请执行以下命令以更新 kubelet 配置文件并重启kubelet服务 \033[0m"
        echo "sed -i \"\$ a\\\\$kubelet_insert_content\" /var/lib/kubelet/config.yaml"
        echo "systemctl restart kubelet"
    else
        exit  # echo "Please specify the \'nodetype\' correctly through the \'-n option."
    fi
fi

